package org.wattdepot.cli.commands;

import java.util.List;
import javax.xml.datatype.DatatypeConstants;
import javax.xml.datatype.XMLGregorianCalendar;
import org.wattdepot.client.BadXmlException;
import org.wattdepot.client.MiscClientException;
import org.wattdepot.client.NotAuthorizedException;
import org.wattdepot.client.ResourceNotFoundException;
import org.wattdepot.client.WattDepotClient;
import org.wattdepot.util.tstamp.Tstamp;

/**
 * This class contains a command to figure out what day and time of the month the source
 * was using the most or least amount of power.  It is a modified version of the
 * PowerSamplingCommand.  It was modified to save the date and time when the source was using
 * the most or least amount of power.
 * 
 * Original was by Nathaniel Ashe.
 * @author David Mau
 */
public class EnergyUsageCommand implements WattDepotCliCommand {
  // Default client-server connection to use unless given one.
  private WattDepotClient client = new WattDepotClient(debug);
  
  /**
   * This constructor makes sure that the client really is connected to the server.
   * 
   * @param anotherClient Specifies if the user wants to use another WattDepot server
   * other than the default simulation one.
   */
  public EnergyUsageCommand( String anotherClient ) {
    // If another client is provided
    if ( anotherClient != null ) {
      client = new WattDepotClient( anotherClient );
    }
    
    // Stop right away if we cannot contact server.
    if (!client.isHealthy()) {
      System.out.println("Failed to connect to " + client.getWattDepotUri());
      return;
    }
    // Indicate successful connection.
    //System.out.println("Connected to " + client.getWattDepotUri());
  }

  /**
   * This method returns a String that displays the minimum or maximum amount of 
   * power generated for the source along with when the minimum or maximum occurred.
   * 
   * @param args A list of arguments given to this command.
   * @return A string in MegaWatts of the minimum or maximum power generated for the given 
   * duration.
   */
  public String doCommand(List<String> args) {
    String output = "";
    String resultTime = "";
    double resultPower = 0.0;
    boolean first = true;

    // Check to see if enough arguments were given.
    if (args.size() > 4) {
      output = "Too many arguments.";
      output = output.concat(cr);
      return output;
    }
    if (args.size() < 4) {
      output = "Missing arguments.";
      output = output.concat(cr);
      return output;
    }
    
    // Collect information from arguments.
    String source = args.get(0);
    String startTime = args.get(1);
    String endTime = args.get(2);
    String solution = args.get(3);

    // Convert the times to timestamps.
    XMLGregorianCalendar xmlStartTime = null;
    try {
      xmlStartTime = Tstamp.makeTimestamp(startTime);
    }
    catch (Exception e) {
      output = badTimeStamp;
      output = output.concat(e.toString());
      output = output.concat(cr);
      return output;
    }
    XMLGregorianCalendar xmlEndTime = null;
    try {
      xmlEndTime = Tstamp.makeTimestamp(endTime);
      xmlEndTime = Tstamp.incrementDays(xmlEndTime, -1);
    }
    catch (Exception e) {
      output = badTimeStamp;
      output = output.concat(e.toString());
      output = output.concat(cr);
      return output;
    }

    // Check to see if the end time comes before the start time.
    int temporalTest = xmlStartTime.compare(xmlEndTime);
    if (temporalTest == DatatypeConstants.GREATER) {
      output = endDateBeforeStartDate;
      output = output.concat(cr);
      return output;
    }
    
    // Check to see if the given method is minimum or maximum.
    if ( !"max".equals(solution) && !"min".equals(solution)) {
      output = minOrMax;
      output += cr;
      return output;
    }
    
    // Until the end of the time duration,
    while (xmlStartTime.getDay() <= xmlEndTime.getDay()) {
      double tempPower = 0.0;
      try {
        tempPower = client.getPowerGenerated(source, xmlStartTime) / 1000000;
      }
      catch (NotAuthorizedException e) {
        output = notAuthorized;
        output = output.concat(e.toString());
        output = output.concat(cr);
        return output;
      }
      catch (ResourceNotFoundException e) {
        output = resourceNotFound;
        output = output.concat(e.toString());
        output = output.concat(cr);
        return output;
      }
      catch (BadXmlException e) {
        output = badXml;
        output = output.concat(e.toString());
        output = output.concat(cr);
        return output;
      }
      catch (MiscClientException e) {
        output = miscClient;
        output = output.concat(e.toString());
        output = output.concat(cr);
        return output;
      }

      // If looking for the maximum,
      if ("max".equals(solution)) {
        // Compare the recently calculated power and the recorded power.
        // If the recently calculated power is greater than the recorded power,
        if ( tempPower > resultPower || first ) {
          // Record the recently calculated power and the time.
          resultPower = tempPower;
          resultTime = xmlStartTime.toString();
          first = false;
        }
      }
      else {
        // Compare the recently calculated power and the recorded power.
        // If the recently calculated power is less than the recorded power,
        if ( tempPower < resultPower || first ) {
          // Record the recently calculated power and the time.
          resultPower = tempPower;
          resultTime = xmlStartTime.toString();
          first = false;
        }
      }
      // Increment the start time by 1 hour.
      xmlStartTime = Tstamp.incrementMinutes(xmlStartTime, 60);
    }

    output = "Time: " + resultTime + "  Power: " + resultPower + " MegaWatts" +  cr;
    return output;
  }
}
